﻿// Copyright (c) Adam Nathan.  All rights reserved.
//
// By purchasing the book that this source code belongs to, you may use and
// modify this code for commercial and non-commercial applications, but you
// may not publish the source code.
// THE SOURCE CODE IS PROVIDED "AS IS", WITH NO WARRANTIES OR INDEMNITIES.
using System;
using System.ComponentModel;
using System.IO;
using System.IO.IsolatedStorage;
using Microsoft.Xna.Framework.Audio;

namespace CetWin
{
  public class Recording : INotifyPropertyChanged
  {
    // The backing fields
    string filename;
    string label;
    DateTimeOffset timeStamp;
    TimeSpan duration;

    // The properties, which raise change notifications
    public string Filename
    {
      get { return this.filename; }
      set { this.filename = value; OnPropertyChanged("Filename"); }
    }
    public string Label
    {
      get { return this.label; }
      set { this.label = value; OnPropertyChanged("Label"); 
            // Raise notifications for the readonly properties based on Label    
            OnPropertyChanged("Title"); OnPropertyChanged("ShortTitle"); 
            OnPropertyChanged("Subtitle"); }
    }
    public DateTimeOffset TimeStamp
    {
      get { return this.timeStamp; }
      set { this.timeStamp = value; OnPropertyChanged("TimeStamp"); 
            // Raise notifications for the readonly properties based on TimeStamp    
            OnPropertyChanged("Title"); OnPropertyChanged("ShortTitle"); 
            OnPropertyChanged("Subtitle"); }
    }
    public TimeSpan Duration
    {
      get { return this.duration; }
      set { this.duration = value; OnPropertyChanged("Duration"); 
            // Raise notifications for the readonly properties based on Duration    
            OnPropertyChanged("Title"); OnPropertyChanged("ShortTitle"); 
            OnPropertyChanged("Subtitle"); }
    }

    // A few computed properties for display purposes
    public string Title
    {
      get {
        return String.Format("{0} ({1:00}:{2:00})",
          this.label ?? this.TimeStamp.LocalDateTime.ToShortTimeString(), 
          this.Duration.Minutes, Math.Floor(this.Duration.Seconds));
      }
    }
    public string ShortTitle
    {
      get {
        return this.label ?? this.TimeStamp.LocalDateTime.ToShortTimeString();
      }
    }
    public string Subtitle
    {
      get {
        if (this.label != null)
          return String.Format("{0} {1}", 
            this.TimeStamp.LocalDateTime.ToShortDateString(), 
            this.TimeStamp.LocalDateTime.ToShortTimeString());
        else
          return this.TimeStamp.LocalDateTime.ToShortDateString();
      }
    }

    // Save the stream to isolated storage
    public void SaveContent(MemoryStream memoryStream)
    {
      // Store the duration of the content, used for display purposes
      this.Duration = Microphone.Default.GetSampleDuration(
                                   (int)memoryStream.Position);

      using (IsolatedStorageFile userStore =
             IsolatedStorageFile.GetUserStoreForApplication())
      using (IsolatedStorageFileStream stream =
             userStore.CreateFile(this.Filename))
      {
        stream.Write(memoryStream.GetBuffer(), 0, (int)memoryStream.Position);
      }
    }

    // Get the raw bytes from the file in isolated storage
    byte[] GetBuffer()
    {
      byte[] buffer = 
        new byte[Microphone.Default.GetSampleSizeInBytes(this.Duration)];
      
      using (IsolatedStorageFile userStore = 
             IsolatedStorageFile.GetUserStoreForApplication())
      using (IsolatedStorageFileStream stream = 
             userStore.OpenFile(this.Filename, FileMode.Open))
      {
        stream.Read(buffer, 0, buffer.Length);
      }
      return buffer;
    }

    // Create and return a sound effect based on the raw bytes in the file
    public SoundEffect GetContent()
    {
      return new SoundEffect(this.GetBuffer(), Microphone.Default.SampleRate, 
        AudioChannels.Mono);
    }

    // Delete the file
    public void DeleteContent()
    {
      using (IsolatedStorageFile userStore =
             IsolatedStorageFile.GetUserStoreForApplication())
        userStore.DeleteFile(this.Filename);
    }

    // Overwrite the file's contents with the audio data reversed
    public void Reverse()
    {
      byte[] buffer = this.GetBuffer();
      using (IsolatedStorageFile userStore = 
             IsolatedStorageFile.GetUserStoreForApplication())
      using (IsolatedStorageFileStream stream = 
             userStore.OpenFile(this.Filename, FileMode.Open, FileAccess.Write))
      {
        // Reverse each 2-byte chunk (each 16-bit audio sample)
        for (int i = buffer.Length - 2; i >= 0; i -= 2)
          stream.Write(buffer, i, 2);
      }
    }

    void OnPropertyChanged(string propertyName)
    {
      PropertyChangedEventHandler handler = this.PropertyChanged;
      if (handler != null)
        handler(this, new PropertyChangedEventArgs(propertyName));
    }

    public event PropertyChangedEventHandler PropertyChanged;
  }
}